Skip to content

refactor(runtime): PermissionDeniedError has ONE declaration again (#7270) - #7462

Merged
os-help merged 1 commit into
mainfrom
claude/issue-7270-permission-denied-error-parity
Aug 10, 2026
Merged

refactor(runtime): PermissionDeniedError has ONE declaration again (#7270)#7462
os-help merged 1 commit into
mainfrom
claude/issue-7270-permission-denied-error-parity

Conversation

@os-help

@os-help os-help commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Fixes #7270

security/resolve-execution-context.ts re-declared PermissionDeniedError and isPermissionDeniedError character-for-character from @objectstack/plugin-security's errors.ts, with a doc comment asking the next editor to keep them "structurally identical" and nothing enforcing it. Both fields of the ADR-0112 denial envelope are load-bearing — statusCode is what the dispatcher answers with, code is what a matcher keys on — so editing one copy's 403 left every test in the repo green while one dispatch path answered a denial with the wrong status.

Route taken: (a), single declaration

@objectstack/plugin-security throws these (23 call sites); the runtime only catches them. The plugin now owns the single declaration and the runtime module re-exports it. @objectstack/plugin-security was already a plain dependencies entry of @objectstack/runtime, so this adds no dependency edge, and tsup externalizes workspace dependencies — the bundle gained an import "@objectstack/plugin-security" and lost the duplicated class (ESM 428.21 KB → 428.02 KB).

The symbols stay exported from the runtime module rather than being deleted, because http-dispatcher.ts imports isPermissionDeniedError from that path. Nothing outside the package is affected: security/index.ts never re-exported either symbol, so neither was reachable from the public barrel.

Why the re-export is safe

The matcher is unchanged and stays duck-typed (name / code / message-prefix, never instanceof) — which is exactly what makes the re-export safe: dual CJS/ESM output and bundling can still hand the two sides distinct class objects. The card's note about the prose-match arm stands as recorded; this PR does not touch it.

The new permission-denied-error-parity.test.ts pins both halves — that the two import paths reach the same declaration (this assertion fails against the old copy), and that an instance built from a deliberately foreign class of the same shape is still matched.

No behaviour change: name, code: 'PERMISSION_DENIED' and statusCode: 403 are byte-identical to what the runtime copy produced.


Implemented by a dispatched dev agent in its own container; PR opened by the PM seat because the container had git push but no GitHub API access. Full rationale is preserved verbatim in the commit message of e775a58bb.


Generated by Claude Code

…7270)

`security/resolve-execution-context.ts` re-declared `PermissionDeniedError`
and `isPermissionDeniedError` character-for-character from
`@objectstack/plugin-security`'s `errors.ts`, with a doc comment asking the
next editor to keep them "structurally identical" and nothing enforcing it.
Both fields of the ADR-0112 denial envelope are load-bearing — `statusCode`
is what the dispatcher answers with, `code` is what a matcher keys on — so
editing one copy's `403` left every test in the repo green while one dispatch
path answered a denial with the wrong status.

`@objectstack/plugin-security` throws these (23 call sites); the runtime only
catches them. The plugin now owns the single declaration and the runtime
module re-exports it. `@objectstack/plugin-security` was already a plain
`dependencies` entry of `@objectstack/runtime`, so this adds no dependency,
and tsup externalizes workspace dependencies — the bundle gained an
`import "@objectstack/plugin-security"` and lost the duplicated class
(ESM 428.21 KB -> 428.02 KB).

The symbols stay exported from the runtime module rather than being deleted,
because `http-dispatcher.ts` imports `isPermissionDeniedError` from that path.
Nothing outside the package is affected: `security/index.ts` never re-exported
either symbol, so neither was reachable from the public barrel.

The matcher is unchanged and stays duck-typed (`name` / `code` /
message-prefix, never `instanceof`), which is what makes the re-export safe:
dual CJS/ESM output and bundling can still hand the two sides distinct class
objects. The new `permission-denied-error-parity.test.ts` pins both halves —
that the two import paths reach the same declaration (this assertion fails
against the old copy), and that an instance built from a deliberately foreign
class of the same shape is still matched.

No behaviour change: `name`, `code: 'PERMISSION_DENIED'` and
`statusCode: 403` are byte-identical to what the runtime copy produced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015TbH9juzW7PvJzbsdpUnEp
@vercel

vercel Bot commented Aug 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 10, 2026 1:38pm

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Aug 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/runtime.

20 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx (via packages/runtime)
  • content/docs/api/index.mdx (via @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime)
  • content/docs/kernel/cluster.mdx (via @objectstack/runtime)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime)
  • content/docs/permissions/system-context.mdx (via packages/runtime)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)

2 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime)
  • content/docs/releases/v17.mdx (via @objectstack/runtime)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-help
os-help marked this pull request as ready for review August 10, 2026 13:50
@os-help
os-help added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 91eddca Aug 10, 2026
26 checks passed
@os-help
os-help deleted the claude/issue-7270-permission-denied-error-parity branch August 10, 2026 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@objectstack/runtime re-declares PermissionDeniedError "structurally identical" to plugin-security's, with nothing enforcing the identity

2 participants